name: Inspektor Gadget CI
env:
  REGISTRY: ghcr.io
  CONTAINER_REPO: ${{ github.repository }}
  GO_VERSION: 1.21.3
  AZURE_AKS_CLUSTER_PREFIX: ig-ci-aks-
  DEFAULT_DNSTESTER_IMAGE: ghcr.io/inspektor-gadget/dnstester:latest
  DEFAULT_EBPF_BUILDER_IMAGE: ghcr.io/inspektor-gadget/ebpf-builder:latest
concurrency:
  group: ${{ github.ref }}
  # We do not want to cancel job in progress on main to be sure to catch new
  # regression as soon as they are introduced.
  cancel-in-progress: ${{ github.ref_name != 'main' }}
on:
  pull_request:
  push:
    branches:
    - main
    - 'release-*'
    - 'citest/**'
    tags:
    - 'v*'

permissions: read-all

# Jobs are given a level in a comment.
# Jobs of the same level run in parallel.
# Jobs of level N depend of, at least, one job on level N - 1 expect job whom
# level is 0.
jobs:
  documentation-checks:
    name: Documentation checks
    # level: 0
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Setup go
      uses: actions/setup-go@v5
      with:
        go-version: ${{ env.GO_VERSION }}
        cache: true
      id: go
    - name: Check if generated files are updated
      run: |
        make manifests generate generate-documentation
        git diff --exit-code HEAD --
    - name: Check that there are not broken links
      uses: gaurav-nelson/github-action-markdown-link-check@v1
      with:
        use-quiet-mode: 'yes'
    - uses: dorny/paths-filter@v3
      id: filter
      with:
        filters: |
          docs:
            - 'docs/**'
    - name: Setup Hugo
      if: steps.filter.outputs.docs == 'true'
      uses: peaceiris/actions-hugo@v2
      with:
        hugo-version: '0.89.0'
        extended: true
    - name: Check website build
      if: steps.filter.outputs.docs == 'true'
      run: |
        cd $RUNNER_TEMP
        git clone https://github.com/inspektor-gadget/website/
        cd website
        mkdir -p external-docs/
        ln -s $GITHUB_WORKSPACE external-docs/inspektor-gadget.git_mainlatest
        make

  actionlint:
    name: Lint GitHub Actions workflows
    # level: 0
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Check workflow files
      shell: bash
      run: |
        # As advised from:
        # https://github.com/rhysd/actionlint/blob/main/docs/usage.md#use-actionlint-on-github-actions
        curl -o download-actionlint.bash https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash
        bash download-actionlint.bash
        # For now, we do not use shellcheck, we may activate it later.
        ./actionlint -color -shellcheck=

  lint:
    name: Lint
    # level: 0
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Setup go
      uses: actions/setup-go@v5
      with:
        go-version: ${{ env.GO_VERSION }}
      id: go
    - name: Lint
      uses: golangci/golangci-lint-action@v4.0.0
      with:
        # This version number must be kept in sync with Makefile lint one.
        version: v1.54.2
        working-directory: /home/runner/work/inspektor-gadget/inspektor-gadget
        # Workaround to display the output:
        # https://github.com/golangci/golangci-lint-action/issues/119#issuecomment-981090648
        args: "--out-${NO_FUTURE}format colored-line-number"

  semgrep:
    name: semgrep
    runs-on: ubuntu-latest

    container:
      image: returntocorp/semgrep

    # Skip any PR created by dependabot to avoid permission issues:
    if: (github.actor != 'dependabot[bot]')

    steps:
      # Fetch project source with GitHub Actions Checkout.
      - uses: actions/checkout@v4
      # Run the "semgrep ci" command on the command line of the docker image.
      - run: cd $GITHUB_WORKSPACE && semgrep ci --config $GITHUB_WORKSPACE/.semgrep_rules.yaml


  ebpf-objects-checks:
    name: eBPF Object checks
    # level: 1
    needs: build-helper-images
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Check ebpf formatting
        run: |
          sudo apt-get update && sudo apt-get install -y clang-format
          make clang-format
          changes="$(git status --porcelain)"
          if [ -n "$changes" ] ; then
            >&2 echo "Use 'make clang-format' to fix the style in the eBPF code:"
            >&2 git diff
            exit 1
          fi
      - name: Detect changes for ebpf objects
        run: |
          make EBPF_BUILDER=${{ needs.build-helper-images.outputs.ebpf_builder_image }} ebpf-objects
          changes="$(git status --porcelain)"
          if [ -n "$changes" ] ; then
            >&2 echo "$changes"
            exit 1
          fi
      - name: Check that testdata is updated
        run: |
          make testdata
          changes="$(git status --porcelain)"
          if [ -n "$changes" ] ; then
            >&2 echo "$changes"
            exit 1
          fi

  pr-dependencies-checks:
    name: PR dependencies checks
    # level: 0
    # We need to run this action only on PR.
    # Otherwise, for other cases like pushing to main, it will fail because it
    # searches for base_ref and head_ref which only exists in PR context.
    if: ${{ github.event.pull_request }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Check if added dependencies do not contain CVE.
        uses: actions/dependency-review-action@v4

  build-clients:
    name: clients
    # level: 0
    runs-on: ubuntu-latest
    permissions:
      security-events: write
    strategy:
      fail-fast: false
      matrix:
        client: [kubectl-gadget, gadgetctl]
        os: [linux, darwin, windows]
        arch: [amd64, arm64]
        exclude:
          - os: windows
            arch: arm64
    steps:
    - uses: actions/checkout@v4
    - name: Setup go
      uses: actions/setup-go@v5
      with:
        go-version: ${{ env.GO_VERSION }}
        cache: true
      id: go
    - name: Set container repository and determine image tag
      id: set-repo-determine-image-tag
      uses: ./.github/actions/set-container-repo-and-determine-image-tag
      with:
        registry: ${{ env.REGISTRY }}
        container-image: ${{ env.CONTAINER_REPO }}
    - uses: github/codeql-action/init@v3
      with:
        languages: go
    - name: Build ${{ matrix.client }}-${{ matrix.os }}-${{ matrix.arch }}
      run: |
        git checkout

        # Prevent releases with -dirty suffix due to forgotten entries in
        # .gitignore.
        changes="$(git status --porcelain)"
        if [ -n "$changes" ] ; then
          echo "$changes"
          exit 1
        fi

        client=${{ matrix.client }}-${{ matrix.os }}-${{ matrix.arch }}

        CONTAINER_REPO=${{ steps.set-repo-determine-image-tag.outputs.container-repo }} \
        IMAGE_TAG=${{ steps.set-repo-determine-image-tag.outputs.image-tag }} \
        make $client

        # We need to append .exe to windows binaries...
        dot_exe=$(test ${{ matrix.os }} = 'windows' && echo '.exe' || echo '')

        # Prepare assets for release and actions artifacts
        platform='${{ matrix.os }}-${{ matrix.arch }}'
        mkdir $platform
        cp "${client}${dot_exe}" "${platform}/${{ matrix.client }}${dot_exe}"
        cp LICENSE $platform/
        tar --sort=name --owner=root:0 --group=root:0 \
          -czf ${client}.tar.gz -C $platform \
          ${{ matrix.client }}${dot_exe} LICENSE
        rm -rf $platform
    - name: CWE checks for ${{ matrix.client }}-${{ matrix.os }}-${{ matrix.arch }}
      uses: github/codeql-action/analyze@v3
      with:
        category: ${{ matrix.client }}-${{ matrix.os }}-${{ matrix.arch }}
    - name: Add ${{ matrix.client }}-${{ matrix.os }}-${{ matrix.arch }}.tar.gz as artifact.
      uses: actions/upload-artifact@v3
      with:
        name: ${{ matrix.client }}-${{ matrix.os }}-${{ matrix.arch }}-tar-gz
        path: /home/runner/work/inspektor-gadget/inspektor-gadget/${{ matrix.client }}-${{ matrix.os }}-${{ matrix.arch }}.tar.gz

  btfgen:
    name: btfgen
    # level: 0
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        platform: [amd64, arm64]
    steps:
    - uses: actions/checkout@v4
    - name: Get btfhub-archive last commmit
      id: get-btfhub-head
      run: |
        echo "head=$(git ls-remote https://github.com/aquasecurity/btfhub-archive/ HEAD | cut -f1)" >> $GITHUB_OUTPUT
      shell: bash
    - name: Cache BTFGen
      id: cache-btfgen
      uses: actions/cache@v4.0.0
      with:
        path: pkg/btfgen/btfs
        # key is composed by
        # - arch: amd64 or arm64
        # - latest commit of btfhub
        # - hash of all bpf objects
        key: btfgen-${{ matrix.platform }}-${{ steps.get-btfhub-head.outputs.head }}-${{ hashFiles('pkg/**/*.o') }}
    - name: BTFGen
      if: ${{ steps.cache-btfgen.outputs.cache-hit != 'true' }}
      run: |
          ./tools/getbtfhub.sh
          ./tools/getbpftool.sh
          make btfgen BPFTOOL=/tmp/bpftool \
              ARCH=${{ matrix.platform }} BTFHUB_ARCHIVE=$HOME/btfhub-archive/ -j$(nproc)

  build-ig:
    name: ig
    # level: 1
    needs:
      - btfgen
      - build-helper-images
    runs-on: ubuntu-latest
    permissions:
      security-events: write
    strategy:
      fail-fast: false
      matrix:
        platform: [amd64, arm64]
    steps:
    - uses: actions/checkout@v4
    - name: Setup go
      uses: actions/setup-go@v5
      with:
        go-version: ${{ env.GO_VERSION }}
        cache: true
      id: go
    - name: Get btfhub-archive last commmit
      id: get-btfhub-head
      run: |
        echo "head=$(git ls-remote https://github.com/aquasecurity/btfhub-archive/ HEAD | cut -f1)" >> $GITHUB_OUTPUT
      shell: bash
    - name: Cache BTFGen
      id: cache-btfgen
      uses: actions/cache@v4.0.0
      with:
        path: pkg/btfgen/btfs
        # key is composed by
        # - arch: amd64 or arm64
        # - latest commit of btfhub
        # - hash of all bpf objects
        key: btfgen-${{ matrix.platform }}-${{ steps.get-btfhub-head.outputs.head }}-${{ hashFiles('pkg/**/*.o') }}
    - name: Build ig-linux-${{ matrix.platform }}
      run: |
        if [ "${{ matrix.platform }}" = 'arm64' ]; then
          sudo apt-get update
          sudo apt-get install qemu-user-static
        fi

        make EBPF_BUILDER=${{ needs.build-helper-images.outputs.ebpf_builder_image }} ig-linux-${{ matrix.platform }}

        # Prepare assets for release and actions artifacts
        mkdir ${{ matrix.platform }}
        cp ig-linux-${{ matrix.platform }} ${{ matrix.platform }}/ig
        cp LICENSE ${{ matrix.platform }}/
        tar --sort=name --owner=root:0 --group=root:0 \
          -czf ig-linux-${{ matrix.platform }}.tar.gz -C ${{ matrix.platform }} \
          ig LICENSE
        rm -rf ${{ matrix.platform }}
    - name: Add ig-linux-${{ matrix.platform }}.tar.gz as artifact.
      uses: actions/upload-artifact@v3
      with:
        name: ig-linux-${{ matrix.platform }}-tar-gz
        path: /home/runner/work/inspektor-gadget/inspektor-gadget/ig-linux-${{ matrix.platform }}.tar.gz

  build-ig-cwe:
    name: Check ig CWE
    # level: 0
    runs-on: ubuntu-latest
    permissions:
      security-events: write
    strategy:
      fail-fast: false
      matrix:
        platform: [amd64, arm64]
    steps:
    - uses: actions/checkout@v4
    - name: Setup go
      uses: actions/setup-go@v5
      with:
        go-version: ${{ env.GO_VERSION }}
        cache: true
      id: go
    - uses: github/codeql-action/init@v3
      with:
        languages: go
    - name: Build ig-linux-${{ matrix.platform }} for CWE checks
      run: |
        # We need to build ig using go build otherwise CodeQL will not detect
        # that the binary was built and will try to autobuild it which adds
        # extra time in the CI pipeline.
        CGO_ENABLED=0 GOARCH=${{ matrix.platform }} go build \
          -ldflags "-extldflags '-static'" \
          github.com/inspektor-gadget/inspektor-gadget/cmd/ig
    - name: CWE checks for ig-linux-${{ matrix.platform }}
      uses: github/codeql-action/analyze@v3
      with:
        category: ig-linux-${{ matrix.platform }}

  build-gadget-container-deps:
    # We only build this dependencies to check if they do not contain CWE.
    name: Build gadget-container-deps
    # level: 0
    runs-on: ubuntu-latest
    permissions:
      security-events: write
    steps:
    - uses: actions/checkout@v4
    - name: Setup go
      uses: actions/setup-go@v5
      with:
        go-version: ${{ env.GO_VERSION }}
        cache: true
      id: go
    - uses: github/codeql-action/init@v3
      with:
        languages: go
    - name: Build gadget-container-deps
      run: |
        make -C gadget-container
    - name: CWE checks for gadget-container-deps
      uses: github/codeql-action/analyze@v3
      with:
        category: gadget-container-deps

  build-gadget-container-images:
    name: gadget img
    # level: 1
    needs: btfgen
    runs-on: ubuntu-latest
    permissions:
      # allow publishing container image
      # in case of public fork repo/packages permissions will always be read
      contents: read
      packages: write
    outputs:
      digest-amd64: ${{ steps.published-gadget-container-images.outputs.amd64 }}
      digest-arm64: ${{ steps.published-gadget-container-images.outputs.arm64 }}
    strategy:
      fail-fast: false
      matrix:
        os: [ linux ]
        # For the moment, we only support these two platforms.
        platform: [ arm64, amd64 ]
    steps:
    - uses: actions/checkout@v4
    - name: Set up QEMU
      uses: docker/setup-qemu-action@v3
    - name: Set up Docker Buildx
      id: buildx
      uses: docker/setup-buildx-action@v3
    - name: Cache Docker layers
      uses: actions/cache@v4.0.0
      with:
        path: /tmp/.buildx-cache
        key: ${{ runner.os }}-docker-${{ matrix.platform }}-${{ hashFiles('Dockerfiles/gadget.Dockerfile') }}
        restore-keys: |
          ${{ runner.os }}-docker-${{ matrix.platform }}-
    - name: Login to Container Registry
      uses: docker/login-action@v3
      with:
        registry: ${{ env.REGISTRY }}
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}
    - name: Set container repository and determine image tag
      id: set-repo-determine-image-tag
      uses: ./.github/actions/set-container-repo-and-determine-image-tag
      with:
        registry: ${{ env.REGISTRY }}
        container-image: ${{ env.CONTAINER_REPO }}
    - name: Get btfhub-archive last commmit
      id: get-btfhub-head
      run: |
        echo "head=$(git ls-remote https://github.com/aquasecurity/btfhub-archive/ HEAD | cut -f1)" >> $GITHUB_OUTPUT
      shell: bash
    - name: Cache BTFGen
      id: cache-btfgen
      uses: actions/cache@v4.0.0
      with:
        path: pkg/btfgen/btfs
        # key is composed by
        # - arch: amd64 or arm64
        # - latest commit of btfhub
        # - hash of all bpf objects
        key: btfgen-${{ matrix.platform }}-${{ steps.get-btfhub-head.outputs.head }}-${{ hashFiles('pkg/**/*.o') }}
    # we are using cache-to mode=min (default) implying that only final image layers are cached, using cache
    # mode=max results in builder image layer of ~7GB because of btfhub files in a layer, which is too
    # large (gloabal limit 10GB) to work with GH caches. (TODO: if we can work with mode=max in future?)
    - name: Build gadget ${{ matrix.os }} ${{ matrix.platform }} container image as artifacts
      uses: docker/build-push-action@v5
      with:
        context: /home/runner/work/inspektor-gadget/inspektor-gadget/
        file: /home/runner/work/inspektor-gadget/inspektor-gadget/Dockerfiles/gadget.Dockerfile
        outputs: type=docker,dest=/tmp/gadget-container-image-${{ matrix.os }}-${{ matrix.platform }}.tar
        tags: ${{ steps.set-repo-determine-image-tag.outputs.container-repo }}:${{ steps.set-repo-determine-image-tag.outputs.image-tag }}
        cache-from: type=local,src=/tmp/.buildx-cache
        cache-to: type=local,dest=/tmp/.buildx-cache-new
        platforms: ${{ matrix.os }}/${{ matrix.platform }}
    - name: Publish gadget ${{ matrix.os }} ${{ matrix.platform }} container image as artifacts
      uses: actions/upload-artifact@v3
      with:
        name: gadget-container-image-${{ matrix.os }}-${{ matrix.platform }}.tar
        path: /tmp/gadget-container-image-${{ matrix.os }}-${{ matrix.platform }}.tar
        retention-days: 1
    - name: Generate SBOM for gadget ${{ matrix.os }} ${{ matrix.platform }} image as artifacts
      uses: docker/build-push-action@v5
      with:
        context: /home/runner/work/inspektor-gadget/inspektor-gadget/
        file: /home/runner/work/inspektor-gadget/inspektor-gadget/Dockerfiles/gadget.Dockerfile
        outputs: type=local,dest=/tmp/gadget-container-image-${{ matrix.os }}-${{ matrix.platform }}
        tags: ${{ steps.set-repo-determine-image-tag.outputs.container-repo }}:${{ steps.set-repo-determine-image-tag.outputs.image-tag }}
        cache-from: type=local,src=/tmp/.buildx-cache
        cache-to: type=local,dest=/tmp/.buildx-cache-new
        platforms: ${{ matrix.os }}/${{ matrix.platform }}
        # The following permits to generate SBOM:
        # https://github.com/moby/buildkit/issues/2773#issue-1194754388
        build-args: BUILDKIT_SYNTAX=crazymax/dockerfile:sbom
    - name: Publish gadget ${{ matrix.os }} ${{ matrix.platform }} container image SBOM as artifacts
      uses: actions/upload-artifact@v3
      with:
        name: gadget-container-image-${{ matrix.os }}-${{ matrix.platform }}-bom-json
        path: /tmp/gadget-container-image-${{ matrix.os }}-${{ matrix.platform }}/sbom_cyclonedx.json
        retention-days: 1
    # build time will not be increased with this workflow because of internal cache
    # buildx is used here since it allows push-by-digest to avoid platform specific tags
    - name: Publish gadget ${{ matrix.os }} ${{ matrix.platform }} container image to registry
      id: publish-gadget-container-images
      if: github.event_name != 'pull_request'
      uses: docker/build-push-action@v5
      with:
        context: /home/runner/work/inspektor-gadget/inspektor-gadget/
        file: /home/runner/work/inspektor-gadget/inspektor-gadget/Dockerfiles/gadget.Dockerfile
        outputs: type=registry,name=${{ steps.set-repo-determine-image-tag.outputs.container-repo }},push=true,push-by-digest=true
        cache-from: type=local,src=/tmp/.buildx-cache-new
        platforms: ${{ matrix.os }}/${{ matrix.platform }}
    - name: Save gadget ${{ matrix.os }} ${{ matrix.platform }} container image digest output
      id: published-gadget-container-images
      if: github.event_name != 'pull_request'
      run: |
          echo "${{ matrix.platform }}=${{ steps.publish-gadget-container-images.outputs.digest }}" >> $GITHUB_OUTPUT
    # old cache entries aren’t deleted, so the cache size keeps growing
    # remove old cache and move new cache to cache path to workaround the issue
    # https://github.com/docker/build-push-action/issues/252
    - name: Move gadget ${{ matrix.os }} ${{ matrix.platform }} container image cache to correct location
      run: |
          rm -rf /tmp/.buildx-cache
          mv /tmp/.buildx-cache-new /tmp/.buildx-cache

  build-ig-container-images:
    name: ig img
    # level: 1
    needs:
      - btfgen
      - build-helper-images
    runs-on: ubuntu-latest
    permissions:
      # allow publishing container image
      # in case of public fork repo/packages permissions will always be read
      contents: read
      packages: write
    outputs:
      digest-amd64: ${{ steps.published-ig-container-images.outputs.amd64 }}
      digest-arm64: ${{ steps.published-ig-container-images.outputs.arm64 }}
    strategy:
      fail-fast: false
      matrix:
        os: [ linux ]
        # For the moment, we only support these two platforms.
        platform: [ arm64, amd64 ]
    steps:
    - uses: actions/checkout@v4
    - name: Set up QEMU
      uses: docker/setup-qemu-action@v3
    - name: Set up Docker Buildx
      id: buildx
      uses: docker/setup-buildx-action@v3
    - name: Cache Docker layers
      uses: actions/cache@v4.0.0
      with:
        path: /tmp/.buildx-cache
        key: ${{ runner.os }}-docker-${{ matrix.platform }}-${{ hashFiles('Dockerfiles/ig.Dockerfile') }}
        restore-keys: |
          ${{ runner.os }}-docker-${{ matrix.platform }}-
    - name: Login to Container Registry
      uses: docker/login-action@v3
      with:
        registry: ${{ env.REGISTRY }}
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}
    - name: Set container repository and determine image tag
      id: set-repo-determine-image-tag
      uses: ./.github/actions/set-container-repo-and-determine-image-tag
      with:
        registry: ${{ env.REGISTRY }}
        container-image: ${{ github.repository_owner }}/ig
    - name: Get btfhub-archive last commmit
      id: get-btfhub-head
      run: |
        echo "head=$(git ls-remote https://github.com/aquasecurity/btfhub-archive/ HEAD | cut -f1)" >> $GITHUB_OUTPUT
      shell: bash
    - name: Cache BTFGen
      id: cache-btfgen
      uses: actions/cache@v4.0.0
      with:
        path: pkg/btfgen/btfs
        # key is composed by
        # - arch: amd64 or arm64
        # - latest commit of btfhub
        # - hash of all bpf objects
        key: btfgen-${{ matrix.platform }}-${{ steps.get-btfhub-head.outputs.head }}-${{ hashFiles('pkg/**/*.o') }}
    - name: Build ig ${{ matrix.os }} ${{ matrix.platform }} container image as artifacts
      uses: docker/build-push-action@v5
      with:
        context: /home/runner/work/inspektor-gadget/inspektor-gadget/
        file: /home/runner/work/inspektor-gadget/inspektor-gadget/Dockerfiles/ig.Dockerfile
        outputs: type=docker,dest=/tmp/ig-container-image-${{ matrix.os }}-${{ matrix.platform }}.tar
        tags: ${{ steps.set-repo-determine-image-tag.outputs.container-repo }}:${{ steps.set-repo-determine-image-tag.outputs.image-tag }}
        cache-from: type=local,src=/tmp/.buildx-cache
        cache-to: type=local,dest=/tmp/.buildx-cache-new
        platforms: ${{ matrix.os }}/${{ matrix.platform }}
        build-args: |
          VERSION=${{ steps.set-repo-determine-image-tag.outputs.image-tag }}
          EBPF_BUILDER=${{ needs.build-helper-images.outputs.ebpf_builder_image }}
    - name: Publish ig ${{ matrix.os }} ${{ matrix.platform }} container image as artifacts
      uses: actions/upload-artifact@v3
      with:
        name: ig-container-image-${{ matrix.os }}-${{ matrix.platform }}.tar
        path: /tmp/ig-container-image-${{ matrix.os }}-${{ matrix.platform }}.tar
        retention-days: 1
    - name: Generate ig ${{ matrix.os }} ${{ matrix.platform }} container image SBOM as artifacts
      uses: docker/build-push-action@v5
      with:
        context: /home/runner/work/inspektor-gadget/inspektor-gadget/
        file: /home/runner/work/inspektor-gadget/inspektor-gadget/Dockerfiles/ig.Dockerfile
        outputs: type=local,dest=/tmp/ig-container-image-${{ matrix.os }}-${{ matrix.platform }}
        tags: ${{ steps.set-repo-determine-image-tag.outputs.container-repo }}:${{ steps.set-repo-determine-image-tag.outputs.image-tag }}
        cache-from: type=local,src=/tmp/.buildx-cache
        cache-to: type=local,dest=/tmp/.buildx-cache-new
        platforms: ${{ matrix.os }}/${{ matrix.platform }}
        build-args: |
          VERSION=${{ steps.set-repo-determine-image-tag.outputs.image-tag }}
          EBPF_BUILDER=${{ needs.build-helper-images.outputs.ebpf_builder_image }}
          BUILDKIT_SYNTAX=crazymax/dockerfile:sbom
    - name: Publish ig ${{ matrix.os }} ${{ matrix.platform }} container image SBOM as artifacts
      uses: actions/upload-artifact@v3
      with:
        name: ig-container-image-${{ matrix.os }}-${{ matrix.platform }}-bom-json
        path: /tmp/ig-container-image-${{ matrix.os }}-${{ matrix.platform }}/sbom_cyclonedx.json
        retention-days: 1
    # build time will not be increased with this workflow because of internal cache
    # buildx is used here since it allows push-by-digest to avoid platform specific tags
    - name: Publish ig ${{ matrix.os }} ${{ matrix.platform }} container image to registry
      id: publish-ig-container-images
      if: github.event_name != 'pull_request'
      uses: docker/build-push-action@v5
      with:
        context: /home/runner/work/inspektor-gadget/inspektor-gadget/
        file: /home/runner/work/inspektor-gadget/inspektor-gadget/Dockerfiles/ig.Dockerfile
        outputs: type=registry,name=${{ steps.set-repo-determine-image-tag.outputs.container-repo }},push=true,push-by-digest=true
        cache-from: type=local,src=/tmp/.buildx-cache-new
        platforms: ${{ matrix.os }}/${{ matrix.platform }}
        build-args: |
          VERSION=${{ steps.set-repo-determine-image-tag.outputs.image-tag }}
          EBPF_BUILDER=${{ needs.build-helper-images.outputs.ebpf_builder_image }}
    - name: Save ig ${{ matrix.os }} ${{ matrix.platform }} container image digest output
      id: published-ig-container-images
      if: github.event_name != 'pull_request'
      run: |
          echo "${{ matrix.platform }}=${{ steps.publish-ig-container-images.outputs.digest }}" >> $GITHUB_OUTPUT
    # old cache entries aren’t deleted, so the cache size keeps growing
    # remove old cache and move new cache to cache path to workaround the issue
    # https://github.com/docker/build-push-action/issues/252
    - name: Move ig ${{ matrix.os }} ${{ matrix.platform }} container image cache to correct location
      run: |
          rm -rf /tmp/.buildx-cache
          mv /tmp/.buildx-cache-new /tmp/.buildx-cache

  scan-gadget-container-images:
    name: Scan gadget img
    # level: 2
    needs: build-gadget-container-images
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        os: [ linux ]
        platform: [ amd64 ]
    steps:
      - name: Download gadget ${{ matrix.os }} ${{ matrix.platform }} container image as artifacts
        uses: actions/download-artifact@v3
        with:
          name: gadget-container-image-${{ matrix.os }}-${{ matrix.platform }}.tar
          path: ${{ github.workspace }}
      - name: Scan gadget ${{ matrix.os }} ${{ matrix.platform }} container image
        uses: aquasecurity/trivy-action@84384bd6e777ef152729993b8145ea352e9dd3ef # v0.17.0
        with:
          input: gadget-container-image-${{ matrix.os }}-${{ matrix.platform }}.tar
          format: 'table'
          exit-code: 1
          severity: CRITICAL,HIGH
          # uncomment to ignore vulnerabilities
          ignore-unfixed: true
          # ignore-policy: .github/trivy/ignore-policy.yaml

  publish-gadget-images-manifest:
    name: Publish gadget img manifest
    # level: 2
    if: github.event_name != 'pull_request'
    needs:
      - build-gadget-container-images
      - public-key-check
    runs-on: ubuntu-latest
    permissions:
      # allow publishing container image
      # in case of public fork repo/packages permissions will always be read
      contents: read
      packages: write
    strategy:
      fail-fast: false
    outputs:
      image-digest: ${{ steps.publish-manifest-list.outputs.image-digest }}
    steps:
      - uses: actions/checkout@v4
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      - name: Login to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Set container repository and determine image tag
        id: set-repo-determine-image-tag
        uses: ./.github/actions/set-container-repo-and-determine-image-tag
        with:
          registry: ${{ env.REGISTRY }}
          container-image: ${{ env.CONTAINER_REPO }}
      - name: Publish the manifest list
        id: publish-manifest-list
        run: |
          IMAGE_TAG=${{ steps.set-repo-determine-image-tag.outputs.container-repo }}:${{ steps.set-repo-determine-image-tag.outputs.image-tag }}
          IMAGE_SOURCE="https://github.com/inspektor-gadget/inspektor-gadget"
          IMAGE_DOCUMENTATION="https://inspektor-gadget.io/docs"
          IMAGE_LICENSES="Apache-2.0"
          IMAGE_TITLE="Inspektor Gadget k8s DaemonSet"
          IMAGE_DESCRIPTION="Inspektor Gadget is a collection of tools (or gadgets) to debug and inspect Kubernetes resources and applications. This image is used as a long-running DaemonSet in Kubernetes via the kubectl-gadget deploy command or via the Helm charts."

          docker buildx imagetools create \
              -t $IMAGE_TAG \
              --annotation index:org.opencontainers.image.documentation="$IMAGE_DOCUMENTATION" \
              --annotation index:org.opencontainers.image.description="$IMAGE_DESCRIPTION" \
              --annotation index:org.opencontainers.image.licenses="$IMAGE_LICENSES" \
              --annotation index:org.opencontainers.image.source="$IMAGE_SOURCE" \
              --annotation index:org.opencontainers.image.title="$IMAGE_TITLE" \
              ${{ steps.set-repo-determine-image-tag.outputs.container-repo }}@${{ needs.build-gadget-container-images.outputs.digest-amd64 }} \
              ${{ steps.set-repo-determine-image-tag.outputs.container-repo }}@${{ needs.build-gadget-container-images.outputs.digest-arm64 }}

          image_digest=$(docker buildx imagetools inspect $IMAGE_TAG | grep 'Digest' | awk '{ print $2 }')
          echo "image-digest=${image_digest}" >> $GITHUB_OUTPUT
      - name: Install Cosign
        uses: sigstore/cosign-installer@main
      - name: Sign the manifest list
        env:
          COSIGN_PASSWORD: '${{ secrets.COSIGN_PASSWORD }}'
          COSIGN_PRIVATE_KEY: '${{ secrets.COSIGN_PRIVATE_KEY }}'
        run: |
          cosign sign --key env://COSIGN_PRIVATE_KEY --yes --recursive "${{ steps.set-repo-determine-image-tag.outputs.container-repo }}@${{ steps.publish-manifest-list.outputs.image-digest }}"

  publish-ig-images-manifest:
    name: Publish ig img manifest
    # level: 2
    if: github.event_name != 'pull_request'
    needs: build-ig-container-images
    runs-on: ubuntu-latest
    permissions:
      # allow publishing container image
      # in case of public fork repo/packages permissions will always be read
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      - name: Login to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Set container repository and determine image tag
        id: set-repo-determine-image-tag
        uses: ./.github/actions/set-container-repo-and-determine-image-tag
        with:
          registry: ${{ env.REGISTRY }}
          container-image: ${{ github.repository_owner }}/ig
      - name: Publish the manifest list
        run: |
          IMAGE_SOURCE="https://github.com/inspektor-gadget/inspektor-gadget"
          IMAGE_DOCUMENTATION="https://inspektor-gadget.io/docs"
          IMAGE_LICENSES="Apache-2.0"
          IMAGE_TITLE="Inspektor Gadget ig tool"
          IMAGE_DESCRIPTION="Inspektor Gadget is a collection of tools (or gadgets) to debug and inspect Kubernetes resources and applications. This image only includes the ig binary, a standalone tool to run the gadgets."

          docker buildx imagetools create \
            -t ${{ steps.set-repo-determine-image-tag.outputs.container-repo }}:${{ steps.set-repo-determine-image-tag.outputs.image-tag }} \
            ${{ steps.set-repo-determine-image-tag.outputs.container-repo }}@${{ needs.build-ig-container-images.outputs.digest-amd64 }} \
            ${{ steps.set-repo-determine-image-tag.outputs.container-repo }}@${{ needs.build-ig-container-images.outputs.digest-arm64 }} \
            --annotation index:org.opencontainers.image.documentation="$IMAGE_DOCUMENTATION" \
            --annotation index:org.opencontainers.image.description="$IMAGE_DESCRIPTION" \
            --annotation index:org.opencontainers.image.licenses="$IMAGE_LICENSES" \
            --annotation index:org.opencontainers.image.source="$IMAGE_SOURCE" \
            --annotation index:org.opencontainers.image.title="$IMAGE_TITLE"

  build-helper-images:
    # level: 0
    name: helper images
    runs-on: ubuntu-latest
    outputs:
      dnstester_image: ${{ steps.image-tag.outputs.dnstester || env.DEFAULT_DNSTESTER_IMAGE }}
      ebpf_builder_image: ${{ steps.image-tag.outputs.ebpf-builder || env.DEFAULT_EBPF_BUILDER_IMAGE }}
    permissions:
      # allow publishing container image
      # in case of public fork repo/packages permissions will always be read
      contents: read
      packages: write
    strategy:
      fail-fast: false
      matrix:
        image:
          - name: "dnstester"
            context: "tools/dnstester"
            dockerfile: "tools/dnstester/Dockerfile"
            platform: "linux/amd64,linux/arm64"
            filter-patterns:
              - "tools/dnstester/*"
          - name: "ebpf-builder"
            context: "/home/runner/work/inspektor-gadget/inspektor-gadget"
            dockerfile: "Dockerfiles/ebpf-builder.Dockerfile"
            platform: "linux/amd64,linux/arm64"
            filter-patterns:
              - "include/**"
              - "Dockerfiles/ebpf-builder.Dockerfile"
              - "cmd/common/image/Makefile.build"
    steps:
    - uses: actions/checkout@v4
    - uses: dorny/paths-filter@v3
      id: filter
      with:
        # https://github.com/rhysd/actionlint/blob/main/docs/checks.md#check-type-check-expression
        filters: |
          pattern: ${{ toJson(matrix.image.filter-patterns) }}
    - name: Check if we should build helpers
      id: check-build-helpers
      if: steps.filter.outputs.pattern == 'true' || startsWith(github.ref_name, 'v')
      run: |
          echo "build=true" >> $GITHUB_OUTPUT
    - name: Set up Docker Buildx
      if: steps.check-build-helpers.outputs.build == 'true'
      uses: docker/setup-buildx-action@v3
    - name: Login to Container Registry
      if: steps.check-build-helpers.outputs.build == 'true'
      uses: docker/login-action@v3
      with:
        registry: ${{ env.REGISTRY }}
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}
    - name: Set container repository and determine image tag
      if: steps.check-build-helpers.outputs.build == 'true'
      id: set-repo-determine-image-tag
      uses: ./.github/actions/set-container-repo-and-determine-image-tag
      with:
        registry: ${{ env.REGISTRY }}
        container-image: ${{ github.repository_owner }}/${{ matrix.image.name }}
    - name: Build ${{ matrix.image.name }} image
      id: build-image
      if: steps.check-build-helpers.outputs.build == 'true'
      uses: docker/build-push-action@v5
      with:
        context: ${{ matrix.image.context }}
        file: ${{ matrix.image.dockerfile }}
        push: ${{ vars.PUSH_HELPERS == 'ENABLE_PUSH_HELPERS' }}
        tags: ${{ steps.set-repo-determine-image-tag.outputs.container-repo }}:${{ steps.set-repo-determine-image-tag.outputs.image-tag }}
        platforms: ${{ matrix.image.platform }}
    - name: Save ${{ matrix.image.name }} image tag output
      id: image-tag
      if: steps.build-image.outputs.digest != ''
      run: |
        echo "${{ matrix.image.name }}=${{ steps.set-repo-determine-image-tag.outputs.container-repo }}:${{ steps.set-repo-determine-image-tag.outputs.image-tag }}" >> $GITHUB_OUTPUT

  build-examples:
    name: example
    # level: 0
    runs-on: ubuntu-latest
    permissions:
      # allow publishing container image
      # in case of public fork repo/packages permissions will always be read
      contents: read
      packages: write
    strategy:
      fail-fast: false
      matrix:
        example: [runc-hook, kube-container-collection]
    steps:
    - uses: actions/checkout@v4
    - name: Set up Docker Buildx
      id: buildx
      uses: docker/setup-buildx-action@v3
    - name: Login to Container Registry
      uses: docker/login-action@v3
      with:
        registry: ${{ env.REGISTRY }}
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}
    - name: Set container repository and determine image tag
      id: set-repo-determine-image-tag
      uses: ./.github/actions/set-container-repo-and-determine-image-tag
      with:
        registry: ${{ env.REGISTRY }}
        container-image: ${{ env.CONTAINER_REPO }}
    - name: Build example container
      uses: docker/build-push-action@v5
      with:
        context: /home/runner/work/inspektor-gadget/inspektor-gadget
        file: /home/runner/work/inspektor-gadget/inspektor-gadget/examples/${{ matrix.example }}/Dockerfile
        push: ${{ secrets.PUSH_EXAMPLES == 'ENABLE_PUSH_EXAMPLES' }}
        tags: ${{ steps.set-repo-determine-image-tag.outputs.container-repo }}-${{ matrix.example }}:${{ steps.set-repo-determine-image-tag.outputs.image-tag }}

  build-gadgets-examples:
    name: Gadgets examples
    # level: 0
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Setup go
      uses: actions/setup-go@v5
      with:
        go-version: ${{ env.GO_VERSION }}
        cache: true
    - name: Build example binaries
      run: |
        for dir in $(dirname $(find examples/gadgets -name README.md)); do
          go build ./$dir;
        done

  test-unit:
    name: Unit tests
    # level: 0
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Setup go
      uses: actions/setup-go@v5
      with:
        go-version: ${{ env.GO_VERSION }}
        cache: true
      id: go
    - name: Basic unit tests
      run: |
        make test
    - name: Gadgets unit tests
      run: |
        make gadgets-unit-tests
    - name: Controller unit tests
      run: |
        make controller-tests

  benchmarks:
    name: Benchmarks
    # level: 0
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Setup go
      uses: actions/setup-go@v5
      with:
        go-version: ${{ env.GO_VERSION }}
        cache: true
      id: go
    - name: Show repository setup
      run: |
        echo "github.event_name: ${{ github.event_name }}"
        echo "github.event.pull_request.head.repo.full_name: ${{ github.event.pull_request.head.repo.full_name }}"
        echo "github.repository: ${{ github.repository }}"
    - name: Run benchmarks
      run: go test -exec sudo -bench=. -run=Benchmark ./pkg/gadgets/... ./internal/benchmarks/... | tee output.txt
    #- name: Download previous benchmark data
    #  uses: actions/cache@v1
    #  with:
    #    path: ./cache
    #    key: ${{ runner.os }}-benchmark
    - name: Store benchmark result
      uses: benchmark-action/github-action-benchmark@v1
      # Disable push from forks or PR from forks.
      # $BENCHMARKS_TOKEN will not be available in those cases.
      if: |
        (github.event_name == 'push' &&
          github.repository == 'inspektor-gadget/inspektor-gadget') ||
        (github.event_name == 'pull_request' &&
          github.event.pull_request.head.repo.full_name == 'inspektor-gadget/inspektor-gadget')
      with:
        name: Gadget benchmarks
        # What benchmark tool the output.txt came from
        tool: 'go'
        # Where the output from the benchmark tool is stored
        output-file-path: output.txt
        # Where the previous data file is stored
        # external-data-json-path: ./cache/benchmark-data.json
        # Workflow will fail when an alert happens
        fail-on-alert: false
        # GitHub API token to make a commit comment
        github-token: ${{ secrets.BENCHMARKS_TOKEN }}
        # Enable alert commit comment
        comment-on-alert: true
        # Enable Job Summary for PRs
        # summary-always: true
        # Mention people in the commit comment
        alert-comment-cc-users: '@alban'
        # Push and deploy GitHub pages branch automatically
        auto-push: ${{ github.repository == 'inspektor-gadget/inspektor-gadget' }}
        gh-pages-branch: gh-pages
        gh-repository: github.com/inspektor-gadget/ig-benchmarks
        benchmark-data-dir-path: dev/bench

  package-helm-charts:
    name: Lint and package Helm charts
    # level: 0
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Set container repository and determine image tag
      id: set-repo-determine-image-tag
      uses: ./.github/actions/set-container-repo-and-determine-image-tag
      with:
        registry: ${{ env.REGISTRY }}
        container-image: ${{ env.CONTAINER_REPO }}
    - name: Install Helm
      uses: azure/setup-helm@v3
      with:
        token: ${{ secrets.GITHUB_TOKEN }}
    # chart version needs to be semver compliant so we remove the leading 'v'
    - name: Set Chart Version for release
      if: startsWith(github.ref, 'refs/tags/v')
      run: |
        TAG=${{ steps.set-repo-determine-image-tag.outputs.image-tag }}
        echo "CHART_VERSION=${TAG#v}" >> $GITHUB_ENV
    - name: Lint Helm charts
      run: |
        export IMAGE_TAG=${{ steps.set-repo-determine-image-tag.outputs.image-tag }}
        make -C charts lint
    - name: Detect changes for deploy.yaml
      run: |
        make generate-manifests
        changes="$(git status --porcelain)"
        if [ -n "$changes" ] ; then
          echo "$changes"
          exit 1
        fi
    - name: Package Helm charts
      run: |
        export IMAGE_TAG=${{ steps.set-repo-determine-image-tag.outputs.image-tag }}
        make -C charts package
    - name: Upload Helm charts
      uses: actions/upload-artifact@v3
      with:
        name: gadget-charts-tgz
        path: charts/bin/*.tgz

  test-ig:
    name: Unit tests for ig
    # level: 0
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Setup go
      uses: actions/setup-go@v5
      with:
        go-version: ${{ env.GO_VERSION }}
        cache: true
      id: go
    - name: Unit tests for ig (as root)
      run: |
        KERNEL=$(uname -r)
        ARCH=$(uname -m)
        if test -f /sys/kernel/btf/vmlinux; then
          echo "BTF is available at /sys/kernel/btf/vmlinux"
        else
          echo "BTF is not available: Trying BTFHub"
          source /etc/os-release
          URL="https://github.com/aquasecurity/btfhub-archive/raw/main/$ID/$VERSION_ID/$ARCH/$KERNEL.btf.tar.xz"
          echo "Trying to download vmlinux from $URL"

          if [[ $(wget -S --spider "$URL" 2>&1 | grep 'HTTP/1.1 200 OK') ]]; then
            wget -q -O /tmp/vmlinux.btf.tar.xz "$URL"
            tar -xvf /tmp/vmlinux.btf.tar.xz
            # Use objcopy to put the btf info in an ELF file as libbpf and cilium/ebpf
            # by default check if there is an ELF file with the .BTF section at
            # /boot/vmlinux-$KERNEL.
            sudo objcopy --input binary --output elf64-little --rename-section .data=.BTF *.btf /boot/vmlinux-$KERNEL
            rm *.btf
            echo "vmlinux downloaded at /boot/vmlinux-$KERNEL"
          else
            echo "vmlinux not found"
          fi
        fi

        make ig-tests

  test-components:
    name: Test components
    # level: 1
    runs-on: ubuntu-latest
    needs:
      - build-helper-images
    steps:
    - uses: actions/checkout@v4
    - name: Setup go
      uses: actions/setup-go@v5
      with:
        go-version: ${{ env.GO_VERSION }}
        cache: true
    - name: Run component tests
      run: |
        make EBPF_BUILDER=${{ needs.build-helper-images.outputs.ebpf_builder_image }} component-tests

  check-secrets:
    name: Check repo secrets
    # level: 0
    runs-on: ubuntu-latest
    outputs:
      aro: ${{ steps.set_output.outputs.aro }}
      aks: ${{ steps.set_output.outputs.aks }}
      gke: ${{ steps.set_output.outputs.gke }}
      cosign: ${{ steps.set_output.outputs.cosign }}
    steps:
      # Secrets cannot be used as if condition, use job output as workaround.
      # https://github.com/actions/runner/issues/520
      - id: set_output
        env:
          OPENSHIFT_SERVER: '${{ secrets.OPENSHIFT_SERVER }}'
          OPENSHIFT_USER: '${{ secrets.OPENSHIFT_USER }}'
          OPENSHIFT_PASSWORD: '${{ secrets.OPENSHIFT_PASSWORD }}'
          AZURE_AKS_CLIENT_ID: '${{ secrets.AZURE_AKS_CLIENT_ID }}'
          AZURE_AKS_TENANT_ID: '${{ secrets.AZURE_AKS_TENANT_ID }}'
          AZURE_AKS_SUBSCRIPTION_ID: '${{ secrets.AZURE_AKS_SUBSCRIPTION_ID }}'
          AZURE_AKS_RESOURCE_GROUP: '${{ secrets.AZURE_AKS_RESOURCE_GROUP }}'
          COSIGN_PASSWORD: '${{ secrets.COSIGN_PASSWORD }}'
          COSIGN_PRIVATE_KEY: '${{ secrets.COSIGN_PRIVATE_KEY }}'
          GKE_PROJECT: '${{ secrets.GKE_PROJECT }}'
          GKE_SERVICE_ACCOUNT: '${{ secrets.GKE_SERVICE_ACCOUNT }}'
          GKE_WORKLOAD_IDENTITY_PROVIDER: '${{ secrets.GKE_WORKLOAD_IDENTITY_PROVIDER }}'
        run: |
          if [[ "${OPENSHIFT_SERVER}" != "" && \
                "${OPENSHIFT_USER}" != "" && \
                "${OPENSHIFT_PASSWORD}" != "" ]]; \
          then
            echo "Secrets to use an ARO cluster were configured in the repo"
            echo "aro=true" >> $GITHUB_OUTPUT
          else
            echo "Secrets to use an ARO cluster were not configured in the repo"
            echo "aro=false" >> $GITHUB_OUTPUT
          fi

          if [[ "${AZURE_AKS_CLIENT_ID}" != "" && \
                "${AZURE_AKS_TENANT_ID}" != "" && \
                "${AZURE_AKS_SUBSCRIPTION_ID}" != "" && \
                "${AZURE_AKS_RESOURCE_GROUP}" != "" ]]; \
          then
            echo "Secrets to use an AKS cluster were configured in the repo"
            echo "aks=true" >> $GITHUB_OUTPUT
          else
            echo "Secrets to use an AKS cluster were not configured in the repo"
            echo "aks=false" >> $GITHUB_OUTPUT
          fi

          if [[ "${COSIGN_PASSWORD}" != "" && \
                "${COSIGN_PRIVATE_KEY}" != "" ]]; \
          then
            echo "Secrets to use cosign were configured in the repo"
            echo "cosign=true" >> $GITHUB_OUTPUT
          else
            echo "Secrets to use cosign were not configured in the repo"
            echo "cosign=false" >> $GITHUB_OUTPUT
          fi

          if [[ "${GKE_PROJECT}" != "" && \
                "${GKE_SERVICE_ACCOUNT}" != "" && \
                "${GKE_WORKLOAD_IDENTITY_PROVIDER}" != "" ]]; \
          then
            echo "Secrets to use a GKE cluster were configured in the repo"
            echo "gke=true" >> $GITHUB_OUTPUT
          else
            echo "Secrets to use a GKE cluster were not configured in the repo"
            echo "gke=false" >> $GITHUB_OUTPUT
          fi

  public-key-check:
    name: Public key check
    # level: 1
    needs: check-secrets
    runs-on: ubuntu-latest
    # When this job is run by a PR coming from a fork, it will not have access
    # to secrets.
    # Also, unless specified in the secrets configuration, dependabot cannot access
    # to secrets.
    # So, we skip this job when run by dependabot and from a PR coming from a
    # fork.
    # We still need to run this job on push, otherwise it will not be run when
    # we merge something on main.
    if: github.event_name == 'push' || (github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]')
    steps:
      - uses: actions/checkout@v4
      - name: Install Cosign
        uses: sigstore/cosign-installer@main
      - name: Check if public key is up-to-date.
        env:
          COSIGN_PASSWORD: '${{ secrets.COSIGN_PASSWORD }}'
          COSIGN_PRIVATE_KEY: '${{ secrets.COSIGN_PRIVATE_KEY }}'
        run: |
          cosign public-key --key env://COSIGN_PRIVATE_KEY > inspektor-gadget.pub
          changes="$(git status --porcelain)"
          if [ -n "$changes" ] ; then
            >&2 echo "$changes"
            exit 1
          fi

  test-integration-k8s-ig:
    name: Test ig w/ k8s
    # level: 3
    needs: [ test-unit, test-ig, build-ig, build-helper-images ]
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        runtime: [ docker, containerd, cri-o ]
    steps:
      - uses: actions/checkout@v4
      - name: Setup go
        uses: actions/setup-go@v5
        with:
          go-version: ${{ env.GO_VERSION }}
          cache: true
      - name: Get ig-linux-amd64.tar.gz from artifact.
        uses: actions/download-artifact@v3
        with:
          name: ig-linux-amd64-tar-gz
          path: /home/runner/work/inspektor-gadget/
      - name: Unpack ig-linux-amd64.tar.gz
        run: |
          tar zxvf /home/runner/work/inspektor-gadget/ig-linux-amd64.tar.gz
          mv ig ig-linux-amd64
      - name: Setup minikube
        uses: ./.github/actions/setup-minikube
        with:
          runtime: ${{ matrix.runtime }}
      - name: Run integration for container runtime ${{ matrix.runtime }}
        id: integration-tests
        run: |
          set -o pipefail
          make -C integration/ig/k8s \
            CONTAINER_RUNTIME=${{ matrix.runtime }} \
            DNSTESTER_IMAGE=${{ needs.build-helper-images.outputs.dnstester_image }} \
            -o build test |& tee integration.log
      - name: Prepare and publish test report for container runtime ${{ matrix.runtime }}
        if: always()
        continue-on-error: true
        uses: ./.github/actions/prepare-and-publish-test-reports
        with:
          test-log-file: integration.log
          test-step-conclusion: ${{ steps.integration-tests.conclusion }}
          test-summary-suffix: ${{ matrix.runtime }}

  build-and-push-gadgets:
    name: Build and push gadgets
    # level: 2
    needs: [ build-ig, build-helper-images ]
    runs-on: ubuntu-latest
    permissions:
      # allow publishing container image
      # in case of public fork repo/packages permissions will always be read
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4
      - name: Login to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Set container repository and determine image tag
        id: set-repo-determine-image-tag
        uses: ./.github/actions/set-container-repo-and-determine-image-tag
        with:
          registry: ${{ env.REGISTRY }}
          container-image: ${{ env.CONTAINER_REPO }}
      - name: Get ig-linux-amd64.tar.gz from artifact.
        uses: actions/download-artifact@v3
        with:
          name: ig-linux-amd64-tar-gz
          path: /home/runner/work/inspektor-gadget/
      - name: Unpack ig-linux-amd64.tar.gz
        run: |
          tar zxvf /home/runner/work/inspektor-gadget/ig-linux-amd64.tar.gz
          sudo mv ig /usr/bin/ig
      - name: Build gadgets
        run: |
          make \
          GADGET_REPOSITORY=${{ steps.set-repo-determine-image-tag.outputs.gadget-repository }} \
          GADGET_TAG=${{ steps.set-repo-determine-image-tag.outputs.gadget-tag }} \
          BUILDER_IMAGE=${{ needs.build-helper-images.outputs.ebpf_builder_image }} \
          push-gadgets -o install/ig

  test-integration-non-k8s-ig:
    name: Test ig w/o k8s
    # level: 3
    needs:
      - test-unit
      - test-ig
      - build-ig
      - build-helper-images
      - build-and-push-gadgets
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        runtime: [ docker, containerd ]
    steps:
      - uses: actions/checkout@v4
      - name: Setup go
        uses: actions/setup-go@v5
        with:
          go-version: ${{ env.GO_VERSION }}
          cache: true
      - name: Get ig-linux-amd64.tar.gz from artifact.
        uses: actions/download-artifact@v3
        with:
          name: ig-linux-amd64-tar-gz
          path: /home/runner/work/inspektor-gadget/
      - name: Unpack ig-linux-amd64.tar.gz
        run: |
          tar zxvf /home/runner/work/inspektor-gadget/ig-linux-amd64.tar.gz
          mv ig ig-linux-amd64
      - name: Run integration for container runtime ${{ matrix.runtime }}
        id: integration-tests
        run: |
          set -o pipefail
          make -C integration/ig/non-k8s \
            CONTAINER_RUNTIME=${{ matrix.runtime }} \
            DNSTESTER_IMAGE=${{ needs.build-helper-images.outputs.dnstester_image }} \
            -o build test-${{ matrix.runtime }} |& tee integration.log
      - name: Prepare and publish test report for container runtime ${{ matrix.runtime }}
        if: always()
        continue-on-error: true
        uses: ./.github/actions/prepare-and-publish-test-reports
        with:
          test-log-file: integration.log
          test-step-conclusion: ${{ steps.integration-tests.conclusion }}
          test-summary-suffix: ${{ matrix.runtime }}

  test-integration-aks:
    name: Integration tests on AKS
    # level: 4
    needs:
      - check-secrets
      - test-unit
      - build-clients
      - build-gadget-container-images
      - publish-gadget-images-manifest
      - build-and-push-gadgets
    if: needs.check-secrets.outputs.aks == 'true'
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        os-sku: [Ubuntu, AzureLinux]
        arch: [amd64, arm64]
    environment: aks
    permissions:
      # This is needed to use federated credentials:
      # https://learn.microsoft.com/en-us/azure/developer/github/connect-from-azure?tabs=azure-cli%2Clinux#set-up-azure-login-with-openid-connect-authentication
      id-token: write
      contents: read
    env:
      AZURE_AKS_RESOURCE_GROUP: '${{ secrets.AZURE_AKS_RESOURCE_GROUP }}'
    steps:
    - uses: actions/checkout@v4
    - name: Setup go
      uses: actions/setup-go@v5
      with:
        go-version: ${{ env.GO_VERSION }}
        cache: true
    - name: Set container repository and determine image tag
      id: set-repo-determine-image-tag
      uses: ./.github/actions/set-container-repo-and-determine-image-tag
      with:
        registry: ${{ env.REGISTRY }}
        container-image: ${{ env.CONTAINER_REPO }}
    - uses: azure/login@v1
      name: Login to Azure
      with:
        client-id: ${{ secrets.AZURE_AKS_CLIENT_ID }}
        tenant-id: ${{ secrets.AZURE_AKS_TENANT_ID }}
        subscription-id: ${{ secrets.AZURE_AKS_SUBSCRIPTION_ID }}
    - name: Craft cluster name
      shell: bash
      run: |
        echo "CLUSTER_NAME=${{ env.AZURE_AKS_CLUSTER_PREFIX }}${{ matrix.arch }}-${{ matrix.os-sku }}-${RANDOM}" >> $GITHUB_ENV
    - name: Create AKS cluster ${{ env.CLUSTER_NAME }}
      shell: bash
      run: |
        node_size='Standard_D2s_v5'
        if [ ${{ matrix.arch }} = 'arm64' ]; then
          # 'p' means the node size corresponds to arm64 hardware.
          node_size='Standard_D2ps_v5'
        fi

        # Enable the aks-preview extension to use AzureLinux as --os-sku.
        # This should lead to AKS being deployed on top of AzureLinux.
        # We do not upgrade az because there is a problem doing so in the
        # GitHub Action.
        az extension add --name aks-preview

        # Let's keep thing in the US to avoid data crossing the Atlantic as
        # GitHub data centers are in the US:
        # https://github.blog/2017-10-12-evolution-of-our-data-centers/
        az aks create -l eastus -g ${AZURE_AKS_RESOURCE_GROUP} -n ${{ env.CLUSTER_NAME }} -s $node_size --os-sku ${{ matrix.os-sku }} --no-ssh-key
    - uses: azure/aks-set-context@v3
      name: Set AKS cluster ${{ env.CLUSTER_NAME }} context
      with:
        cluster-name: ${{ env.CLUSTER_NAME }}
        resource-group: ${{ secrets.AZURE_AKS_RESOURCE_GROUP }}
        admin: false
    - name: Run integration tests
      uses: ./.github/actions/run-integration-tests
      with:
        kubernetes_distribution: "aks-${{ matrix.os-sku }}"
        kubernetes_architecture: "${{ matrix.arch }}"
        container_repo: ${{ steps.set-repo-determine-image-tag.outputs.container-repo }}
        image_tag: ${{ steps.set-repo-determine-image-tag.outputs.image-tag }}
        gadget_repository: ${{ steps.set-repo-determine-image-tag.outputs.gadget-repository }}
        gadget_tag: ${{ steps.set-repo-determine-image-tag.outputs.gadget-tag }}
        test_summary_suffix: "${{ matrix.os-sku }}-${{ matrix.arch }}"
    # This step ensures we get fresh credentials before removing the cluster
    - uses: azure/login@v1
      if: always()
      name: Login to Azure
      with:
        client-id: ${{ secrets.AZURE_AKS_CLIENT_ID }}
        tenant-id: ${{ secrets.AZURE_AKS_TENANT_ID }}
        subscription-id: ${{ secrets.AZURE_AKS_SUBSCRIPTION_ID }}
    - name: Delete AKS cluster ${{ env.CLUSTER_NAME }}
      if: always()
      shell: bash
      run: |
        az aks delete -g ${AZURE_AKS_RESOURCE_GROUP} -n ${{ env.CLUSTER_NAME }} --no-wait --yes

  # Integration tests for ARO are separated from others distributions because it
  # is a pre-created cluster. It implies that we need to use a concurrency group
  # to ensure that only one test-integration-aro job runs at a time so that we
  # never try to use IG on that unique ARO cluster from different workflow runs.
  test-integration-aro:
    name: Integration tests on ARO
    # level: 4
    needs:
      - check-secrets
      - test-unit
      - build-clients
      - build-gadget-container-images
      - publish-gadget-images-manifest
      - build-and-push-gadgets
    # Run this job only if an ARO cluster is available on repo secrets. See
    # docs/devel/ci.md for further details.
    if: needs.check-secrets.outputs.aro == 'true'
    runs-on: ubuntu-latest
    concurrency:
      group: no-simultaneous-test-integration-aro
    steps:
    - uses: actions/checkout@v4
    - name: Setup go
      uses: actions/setup-go@v5
      with:
        go-version: ${{ env.GO_VERSION }}
        cache: true
    - name: Authenticate and set ARO cluster context
      # NOTE: This action generates the Kubernetes config file in the current
      # directory. Therefore, it must be run after checking out code otherwise
      # the file will be cleaned up.
      uses: redhat-actions/oc-login@v1
      with:
        # API Server URL
        openshift_server_url: ${{ secrets.OPENSHIFT_SERVER }}
        # Credentials (TODO: Use a functional Service Account, see issue #574)
        openshift_username: ${{ secrets.OPENSHIFT_USER }}
        openshift_password: ${{ secrets.OPENSHIFT_PASSWORD }}
    - name: Set container repository and determine image tag
      id: set-repo-determine-image-tag
      uses: ./.github/actions/set-container-repo-and-determine-image-tag
      with:
        registry: ${{ env.REGISTRY }}
        container-image: ${{ env.CONTAINER_REPO }}
    - name: Run integration tests
      uses: ./.github/actions/run-integration-tests
      with:
        kubernetes_distribution: "aro"
        kubernetes_architecture: "amd64"
        container_repo: ${{ steps.set-repo-determine-image-tag.outputs.container-repo }}
        image_tag: ${{ steps.set-repo-determine-image-tag.outputs.image-tag }}
        gadget_repository: ${{ steps.set-repo-determine-image-tag.outputs.gadget-repository }}
        gadget_tag: ${{ steps.set-repo-determine-image-tag.outputs.gadget-tag }}
        test_summary_suffix: "aro"

  test-integration-eks:
    name: Integration tests on EKS
    # level: 4
    needs:
      - test-unit
      - build-clients
      - build-gadget-container-images
      - publish-gadget-images-manifest
      - build-and-push-gadgets
    if: ${{ vars.AWS_ROLE != '' }}
    runs-on: ubuntu-latest
    # These permissions are needed to interact with GitHub's OIDC Token endpoint.
    permissions:
      id-token: write
      contents: read
    strategy:
      fail-fast: false
      matrix:
        arch: [amd64, arm64]
    env:
      AWS_REGION: us-east-2
      AWS_EKS_CLUSTER_PREFIX: ig-ci-eks-
    steps:
    - uses: actions/checkout@v4
    - name: Setup go
      uses: actions/setup-go@v5
      with:
        go-version: ${{ env.GO_VERSION }}
        cache: true
    - name: Set container repository and determine image tag
      id: set-repo-determine-image-tag
      uses: ./.github/actions/set-container-repo-and-determine-image-tag
      with:
        registry: ${{ env.REGISTRY }}
        container-image: ${{ env.CONTAINER_REPO }}
    - name: Craft cluster name
      shell: bash
      run: |
        echo "CLUSTER_NAME=${{ env.AWS_EKS_CLUSTER_PREFIX }}${{ matrix.arch }}-${RANDOM}" >> $GITHUB_ENV
    # Install eksctl following https://eksctl.io/installation/#for-unix
    - name: Install eksctl
      run: |
        ARCH=$(dpkg-architecture -qDEB_HOST_ARCH)
        PLATFORM=$(uname -s)_$ARCH
        curl -sLO "https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_$PLATFORM.tar.gz"
        curl -sL "https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_checksums.txt" | grep $PLATFORM | sha256sum --check
        tar -xzf eksctl_$PLATFORM.tar.gz -C /tmp && rm eksctl_$PLATFORM.tar.gz
        sudo mv /tmp/eksctl /usr/local/bin
    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v4
      with:
        role-to-assume: ${{ vars.AWS_ROLE }}
        aws-region: ${{ env.AWS_REGION }}
    - name: Create EKS cluster ${{ env.CLUSTER_NAME }}
      shell: bash
      run: |
        # We need to use big nodes, otherwise integration tests fail because the node can't handle
        # many gadgets running on parallel
        node_type='t2.xlarge'
        if [ ${{ matrix.arch }} = 'arm64' ]; then
          node_type='a1.xlarge'
        fi
        eksctl create cluster --name ${{ env.CLUSTER_NAME }} --tags ig-ci=true --node-type $node_type
    - name: Run integration tests
      uses: ./.github/actions/run-integration-tests
      with:
        kubernetes_distribution: "eks-AmazonLinux"
        kubernetes_architecture: "${{ matrix.arch }}"
        container_repo: ${{ steps.set-repo-determine-image-tag.outputs.container-repo }}
        image_tag: ${{ steps.set-repo-determine-image-tag.outputs.image-tag }}
        gadget_repository: ${{ steps.set-repo-determine-image-tag.outputs.gadget-repository }}
        gadget_tag: ${{ steps.set-repo-determine-image-tag.outputs.gadget-tag }}
        test_summary_suffix: "EKS-${{ matrix.arch }}"
    - name: Delete EKS cluster ${{ env.CLUSTER_NAME }}
      if: always()
      shell: bash
      run: |
        eksctl delete cluster --name ${{ env.CLUSTER_NAME }} --wait=false

  test-integration-gke:
    name: Integration tests on GKE
    # level: 4
    if: needs.check-secrets.outputs.gke == 'true'
    needs:
      - check-secrets
      - test-unit
      - build-clients
      - build-gadget-container-images
      - publish-gadget-images-manifest
      - build-and-push-gadgets
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        flavor:
          - arch: amd64
            region: us-east1
            machine_type: e2-standard-2
          - arch: arm64
            region: us-central1
            machine_type: t2a-standard-2
    # Following permissions are needed to use OIDC authentication with GKE.
    permissions:
      id-token: write
      contents: read
    env:
      GKE_CLUSTER_PREFIX: 'ig-ci-gke-'
    steps:
      - uses: actions/checkout@v4
      - name: Setup go
        uses: actions/setup-go@v5
        with:
          go-version: ${{ env.GO_VERSION }}
          cache: true
      - name: Set container repository and determine image tag
        id: set-repo-determine-image-tag
        uses: ./.github/actions/set-container-repo-and-determine-image-tag
        with:
          registry: ${{ env.REGISTRY }}
          container-image: ${{ env.CONTAINER_REPO }}
      - name: Authenticate with GKE
        uses: google-github-actions/auth@v2
        with:
          project_id: ${{ secrets.GKE_PROJECT }}
          service_account: ${{ secrets.GKE_SERVICE_ACCOUNT }}
          workload_identity_provider: ${{ secrets.GKE_WORKLOAD_IDENTITY_PROVIDER }}
      - name: Set up Cloud SDK
        uses: google-github-actions/setup-gcloud@v2
      - name: Craft cluster name
        shell: bash
        run: |
            echo "CLUSTER_NAME=${{ env.GKE_CLUSTER_PREFIX }}${{ matrix.flavor.arch }}-${RANDOM}" >> $GITHUB_ENV
      - name: Create GKE cluster
        run: |
          # arm64 machine types are only available in zones (us-central1-a, us-central1-b, us-central1-f, us-central1-d) in us-central1 region
          extra_args=""
          if [ ${{ matrix.flavor.arch }} = "arm64" ]; then
                extra_args="--node-locations us-central1-a,us-central1-b,us-central1-f"
          fi

          gcloud container clusters create ${{ env.CLUSTER_NAME }} --project ${{ secrets.GKE_PROJECT }} \
            --region ${{ matrix.flavor.region }} --machine-type ${{ matrix.flavor.machine_type }} --num-nodes 1 --disk-size 50 $extra_args
      - name: Set GKE cluster ${{ env.CLUSTER_NAME }} context
        uses: google-github-actions/get-gke-credentials@v2
        with:
          cluster_name: ${{ env.CLUSTER_NAME }}
          location: ${{ matrix.flavor.region }}
      # ARM nodes come with a taint that prevents pods from being scheduled on them.
      # https://cloud.google.com/kubernetes-engine/docs/how-to/prepare-arm-workloads-for-deployment
      - name: Remove taint for arm64 nodes
        if: ${{ matrix.flavor.arch == 'arm64' }}
        run: |
          kubectl taint nodes --all kubernetes.io/arch=arm64:NoSchedule-
      - name: Run integration tests
        uses: ./.github/actions/run-integration-tests
        with:
          kubernetes_distribution: "gke-COS_containerd"
          kubernetes_architecture: ${{ matrix.flavor.arch }}
          container_repo: ${{ steps.set-repo-determine-image-tag.outputs.container-repo }}
          image_tag: ${{ steps.set-repo-determine-image-tag.outputs.image-tag }}
          gadget_repository: ${{ steps.set-repo-determine-image-tag.outputs.gadget-repository }}
          gadget_tag: ${{ steps.set-repo-determine-image-tag.outputs.gadget-tag }}
          test_summary_suffix: "GKE-${{ matrix.flavor.arch }}"
      - name: Delete GKE cluster
        if: always()
        run: |
          gcloud container clusters delete --project ${{ secrets.GKE_PROJECT }} --region ${{ matrix.flavor.region }} ${{ env.CLUSTER_NAME }} --async --quiet

  test-integration-minikube:
    name: Integr. tests
    # level: 3
    needs:
      - test-unit
      - build-clients
      - build-gadget-container-images
      - build-helper-images
      - build-and-push-gadgets
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        runtime: [docker, containerd, cri-o]
    steps:
    - uses: actions/checkout@v4
    - name: Setup go
      uses: actions/setup-go@v5
      with:
        go-version: ${{ env.GO_VERSION }}
        cache: true
    - name: Setup minikube
      uses: ./.github/actions/setup-minikube
      with:
        runtime: ${{ matrix.runtime }}
        multi-node: true
    - name: Get gadget-container-image-linux-amd64.tar from artifact.
      uses: actions/download-artifact@v3
      with:
        name: gadget-container-image-linux-amd64.tar
        path: /home/runner/work/inspektor-gadget/
    - name: Set container repository and determine image tag
      id: set-repo-determine-image-tag
      uses: ./.github/actions/set-container-repo-and-determine-image-tag
      with:
        registry: ${{ env.REGISTRY }}
        container-image: ${{ env.CONTAINER_REPO }}
    - name: Prepare minikube by loading gadget-container-image-linux-amd64.tar
      run: |
        # 'docker load' ensures the image is named correctly e.g podman has issues loading untagged images from archive
        docker load -i /home/runner/work/inspektor-gadget/gadget-container-image-linux-amd64.tar
        minikube image load ${{ steps.set-repo-determine-image-tag.outputs.container-repo }}:${{ steps.set-repo-determine-image-tag.outputs.image-tag }}
    - name: Run integration tests
      uses: ./.github/actions/run-integration-tests
      with:
        kubernetes_distribution: "minikube-github"
        kubernetes_architecture: "amd64"
        container_repo: ${{ steps.set-repo-determine-image-tag.outputs.container-repo }}
        image_tag: ${{ steps.set-repo-determine-image-tag.outputs.image-tag }}
        dnstester_image: ${{ needs.build-helper-images.outputs.dnstester_image }}
        gadget_repository: ${{ steps.set-repo-determine-image-tag.outputs.gadget-repository }}
        gadget_tag: ${{ steps.set-repo-determine-image-tag.outputs.gadget-tag }}
        test_summary_suffix: ${{ matrix.runtime }}
    - if: ${{ matrix.runtime == 'docker' }}
      name: Check that README is up-to-date
      # We do this check here, as we need to run kubectl-gadget against a deployed installation to
      # be able to download a populated catalog. But we only do it for docker, as it's not
      # necessary to check it more than once.
      shell: bash
      run: |
        perl tools/check-readme.pl ./kubectl-gadget README.md


  publish-test-reports:
    name: Publish test reports
    # level: 5
    needs:
      - test-integration-minikube
      - test-integration-aks
      - test-integration-aro
      - test-integration-eks
      - test-integration-gke
      - test-integration-k8s-ig
      - test-integration-non-k8s-ig
    runs-on: ubuntu-latest
    # Skip this job when running on a fork or a PR from a fork.
    if: always() && (
      (github.event_name == 'push' && github.repository == 'inspektor-gadget/inspektor-gadget') ||
      (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'inspektor-gadget/inspektor-gadget'))
    steps:
    - uses: actions/checkout@v4
    - name: Get all reports
      uses: actions/download-artifact@v3
      with:
        name: "test-reports"
    - name: Store test reports
      shell: bash {0}
      run: ./tools/store-test-reports.sh
      env:
        TEST_REPORTS_TOKEN: ${{ secrets.TEST_REPORTS_TOKEN }}

  release:
    name: Release
    # level: 5
    needs:
      - documentation-checks
      - ebpf-objects-checks
      - lint
      - semgrep
      - test-integration-minikube
      - test-integration-aks
      - test-integration-aro
      - test-integration-eks
      - test-components
      - build-ig-cwe
      - test-ig
      - test-integration-k8s-ig
      - test-integration-non-k8s-ig
      - build-examples
      - build-gadgets-examples
      - package-helm-charts
      - check-secrets
      - scan-gadget-container-images
      - publish-gadget-images-manifest
    runs-on: ubuntu-latest
    permissions:
      contents: write
    if: startsWith(github.ref, 'refs/tags/v') && needs.check-secrets.outputs.cosign == 'true'
    steps:
    - uses: actions/checkout@v4
    - id: set-repo-determine-image-tag
      uses: ./.github/actions/set-container-repo-and-determine-image-tag
      with:
        registry: ${{ env.REGISTRY }}
        container-image: ${{ env.CONTAINER_REPO }}
    - name: Build release YAML
      run: |
        export IMAGE_TAG=${{ steps.set-repo-determine-image-tag.outputs.image-tag }}
        export IMAGE="${{ env.REGISTRY }}/${{ env.CONTAINER_REPO }}:${IMAGE_TAG}"

        # Use echo of cat to avoid printing a new line between files.
        echo "$(cat pkg/resources/manifests/deploy.yaml) $(cat pkg/resources/crd/bases/gadget.kinvolk.io_traces.yaml)" > inspektor-gadget-${{ github.ref_name }}.yaml

        perl -pi -e 's@(image:) ".+\"@$1 "$ENV{IMAGE}"@; s@"latest"@"$ENV{IMAGE_TAG}"@;' inspektor-gadget-${{ github.ref_name }}.yaml
    - name: Create Draft Release
      id: create_release
      uses: softprops/action-gh-release@v1
      with:
        token: ${{ secrets.GITHUB_TOKEN }}
        name: Release ${{ github.ref_name }}
        draft: true
    - name: Get all artifacts.
      uses: actions/download-artifact@v3
    - name: Setup go
      uses: actions/setup-go@v5
      with:
        go-version: ${{ env.GO_VERSION }}
        cache: true
      id: go
    - name: Build ig distributions packages
      run: |
        go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest

        mkdir ig_packages
        for ig_archive in ig-*-*-tar-gz/ig-*-*.tar.gz; do
          cp .nfpm_template.yaml nfpm.yaml

          mkdir archive_output
          tar zxvf $ig_archive -C archive_output
          export path=$(find archive_output -name 'ig')

          # Fill the template file with corresponding information.
          export arch=$(echo $ig_archive | cut -d'-' -f3)
          perl -pi -e 's/IG_ARCH/$ENV{arch}/; s/IG_VERSION/${{ github.ref_name }}/; s/IG_PATH/$ENV{path}/' nfpm.yaml

          # Build the packages
          for distro in apk deb rpm archlinux; do
            package=$(nfpm package -p $distro | grep 'created package' | cut -d':' -f2)

            mv $package ig_packages
          done

          rm -r archive_output
          rm nfpm.yaml
        done
    - name: Rename all artifacts to *-${{ github.ref_name }}.tar.gz
      shell: bash
      run: |
        for i in kubectl-gadget-*-*-tar-gz/kubectl-gadget-*-*.tar.gz ig-*-*-tar-gz/ig-*-*.tar.gz gadgetctl-*-*-tar-gz/gadgetctl-*-*.tar.gz; do
          mv $i $(dirname $i)/$(basename $i .tar.gz)-${{ github.ref_name }}.tar.gz
        done
    - name: Compute checksums for all artifacts
      shell: bash
      run: |
        for i in kubectl-gadget-*-*-tar-gz/kubectl-gadget-*-*.tar.gz ig-*-*-tar-gz/ig-*-*.tar.gz gadgetctl-*-*-tar-gz/gadgetctl-*-*.tar.gz inspektor-gadget-${{ github.ref_name }}.yaml ig_packages/*; do
          hash=$(sha256sum $i | cut -d' ' -f1)
          echo "${hash}  $(basename $i)" >> SHA256SUMS
        done
    - name: Install cyclonedx-gomod
      uses: CycloneDX/gh-gomod-generate-sbom@v2
    - name: Compute SBOM for all binary artifacts
      shell: bash
      run: |
        mkdir sbom

        for i in kubectl-gadget-*-*-tar-gz/kubectl-gadget-*-*.tar.gz ig-*-*-tar-gz/ig-*-*.tar.gz gadgetctl-*-*-tar-gz/gadgetctl-*-*.tar.gz; do
          temp_dir=$(mktemp -d)
          tar zxvf $i -C $temp_dir

          exe=$(find $temp_dir -type f -executable)

          cyclonedx-gomod bin -json -output sbom/$(basename $i .tar.gz).bom.json -version ${{ github.ref_name }} $exe

          rm -fr $temp_dir
        done
    - name: Install Cosign
      uses: sigstore/cosign-installer@main
    - name: Sign checksums file
      shell: bash
      env:
        COSIGN_PASSWORD: '${{ secrets.COSIGN_PASSWORD }}'
        COSIGN_PRIVATE_KEY: '${{ secrets.COSIGN_PRIVATE_KEY }}'
      run: |
        checksums_file=SHA256SUMS

        cosign sign-blob --key env://COSIGN_PRIVATE_KEY --yes $checksums_file --output-signature="${checksums_file}.sig" --bundle="${checksums_file}.bundle"

        # Derivate public key from private key to publish it as release
        # artifact, so people can verify our signature.
        cosign public-key --key env://COSIGN_PRIVATE_KEY > inspektor-gadget.pub
    - name: Rename containers SBOMs
      shell: bash
      run: |
        for i in *-bom-json; do
          mv $i/sbom_cyclonedx.json $(basename $i -bom-json)-${{ github.ref_name }}.bom.json
        done
    - name: Login to Container Registry
      uses: docker/login-action@v3
      with:
        registry: ${{ env.REGISTRY }}
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}
    - name: Upload kubectl-gadget binary
      uses: csexton/release-asset-action@v3
      with:
        pattern: "kubectl-gadget-*-*-tar-gz/kubectl-gadget-*-*.tar.gz"
        github-token: ${{ secrets.GITHUB_TOKEN }}
        release-url: ${{ steps.create_release.outputs.upload_url }}
    - name: Upload IG *.tar.gz binary
      uses: csexton/release-asset-action@v3
      with:
        pattern: "ig-*-*-tar-gz/ig-*-*.tar.gz"
        github-token: ${{ secrets.GITHUB_TOKEN }}
        release-url: ${{ steps.create_release.outputs.upload_url }}
    - name: Upload gadgetctl *.tar.gz binary
      uses: csexton/release-asset-action@v3
      with:
        pattern: "gadgetctl-*-*-tar-gz/gadgetctl-*-*.tar.gz"
        github-token: ${{ secrets.GITHUB_TOKEN }}
        release-url: ${{ steps.create_release.outputs.upload_url }}
    - name: Upload YAML
      uses: csexton/release-asset-action@v3
      with:
        file: inspektor-gadget-${{ github.ref_name }}.yaml
        github-token: ${{ secrets.GITHUB_TOKEN }}
        release-url: ${{ steps.create_release.outputs.upload_url }}
    - name: Upload checksums file
      uses: csexton/release-asset-action@v3
      with:
        file: SHA256SUMS
        github-token: ${{ secrets.GITHUB_TOKEN }}
        release-url: ${{ steps.create_release.outputs.upload_url }}
    - name: Upload IG distributions packages
      uses: csexton/release-asset-action@v3
      with:
        pattern: "ig_packages/ig*"
        github-token: ${{ secrets.GITHUB_TOKEN }}
        release-url: ${{ steps.create_release.outputs.upload_url }}
    - name: Upload Inpektor Gadget Helm Charts
      uses: csexton/release-asset-action@v3
      with:
        pattern: "gadget-charts-tgz/gadget-*.tgz"
        github-token: ${{ secrets.GITHUB_TOKEN }}
        release-url: ${{ steps.create_release.outputs.upload_url }}
    - name: Upload public key
      uses: csexton/release-asset-action@v3
      with:
        pattern: "*.pub"
        github-token: ${{ secrets.GITHUB_TOKEN }}
        release-url: ${{ steps.create_release.outputs.upload_url }}
    - name: Upload bundle
      uses: csexton/release-asset-action@v3
      with:
        pattern: "*.bundle"
        github-token: ${{ secrets.GITHUB_TOKEN }}
        release-url: ${{ steps.create_release.outputs.upload_url }}
    - name: Upload signature
      uses: csexton/release-asset-action@v3
      with:
        pattern: "*.sig"
        github-token: ${{ secrets.GITHUB_TOKEN }}
        release-url: ${{ steps.create_release.outputs.upload_url }}
    - name: Upload container images SBOMs
      uses: csexton/release-asset-action@v3
      with:
        pattern: "*.bom.json"
        github-token: ${{ secrets.GITHUB_TOKEN }}
        release-url: ${{ steps.create_release.outputs.upload_url }}
    - name: Upload binaries SBOMs
      uses: csexton/release-asset-action@v3
      with:
        pattern: "sbom/*.bom.json"
        github-token: ${{ secrets.GITHUB_TOKEN }}
        release-url: ${{ steps.create_release.outputs.upload_url }}
